/**
 ** 访存保留站，对于站内的指令，他们可能存在两次发射
 ** 1. 计算地址，这里对应了rs + imm 计算访存的地址，发射到运算单元
 ** 2. 访存运算，这里将地址+数据发射到存储器单元，得到对应的结果
**/
module MemSaveStation(
    input wire clk,
    input wire save_en_1,                  //保存到保留站的使能信号
    input wire save_en_2,
    input wire [11:0] pc_1, pc_2,
    input wire [2:0] work_mode_1,           //运算模式--普通整数运算 or 整数乘除法 or 浮点
    input wire [2:0] work_mode_2,
    input wire [3:0] alu_ctrl_1,           //运算器的控制信号
    input wire [3:0] alu_ctrl_2,  
    input wire [31:0] imm_1, imm_2,        //立即数的输入  
    input wire rs_1_ready,                 //寄存器是否准备就绪的标记
    input wire rt_1_ready,             
    input wire rs_2_ready,             
    input wire rt_2_ready,             
    input wire [4:0] rs_1_relation,    //和rs寄存器关联的ROB号
    input wire [4:0] rt_1_relation,    //和rt寄存器关联的ROB号
    input wire [4:0] rd_1_relation,    //和rd寄存器关联的ROB号
    input wire [4:0] rs_2_relation,    //和rs寄存器关联的ROB号
    input wire [4:0] rt_2_relation,    //和rt寄存器关联的ROB号
    input wire [4:0] rd_2_relation,    //和rd寄存器关联的ROB号
    input wire rd_1_flag, rd_2_flag,
    input wire [31:0] rs_1_value,      //寄存器的值
    input wire [31:0] rt_1_value,      
    input wire [31:0] rs_2_value,      //寄存器的值
    input wire [31:0] rt_2_value,
    input wire [2:0] dm_rd_ctrl_1, dm_rd_ctrl_2,  //RAM读取控制信号
    input wire [1:0] dm_wr_ctrl_1, dm_wr_ctrl_2,  //RAM写入控制信号
    input wire alu_commit_en, mul_commit_en, div_commit_en, specific_commit_en, mem_commit_en,
    input wire alu_commit_en_1, alu_commit_en_2, mul_commit_en_1, mul_commit_en_2,
    input wire [31:0] alu_commit_value_1, alu_commit_value_2, mul_commit_value_1, mul_commit_value_2,
    input wire [4:0] alu_commit_save_no_1, alu_commit_save_no_2, mul_commit_save_no_1, mul_commit_save_no_2, 
    input wire [4:0] alu_commit_rob_no_1, alu_commit_rob_no_2, mul_commit_rob_no_1, mul_commit_rob_no_2, 
    output reg [31:0] address_x_1, address_y_1, address_x_2, address_y_2,
    output reg [3:0] address_ctrl_1, address_ctrl_2,
    output reg address_ready_en_1, address_ready_en_2,
    output reg [4:0] address_save_no_1, address_save_no_2, address_rob_no_1, address_rob_no_2,
    output reg [31:0] mem_address_1, mem_content_1, mem_address_2, mem_content_2,
    output reg [2:0] mem_rd_ctrl_1, mem_rd_ctrl_2,
    output reg [1:0] mem_wr_ctrl_1, mem_wr_ctrl_2,
    output reg mem_read_en_1, mem_write_en_1, mem_read_en_2, mem_write_en_2,
    output reg [4:0] mem_save_no_1, mem_save_no_2, mem_rob_no_1, mem_rob_no_2
);
    //保留站的一些数组，用来存储在此地等待的指令的信息
    reg [31:0] rs_ok, rt_ok, item_ok, address_ok;                          //寄存器是否准备好的标记位
    reg [31:0] rs_value[0:15], rt_value[0:15], imm[0:15];      //寄存器对应的值
    reg [4:0] rs_relation[0:15], rt_relation[0:15], rd_relation[0:15];  
    reg [1:0] dm_write_ctrl[0:15];
    reg [2:0] dm_read_ctrl[0:15];
    reg [31:0] rd_flag;
    reg [11:0] pc[0:15];

    reg [3:0] alu_ctrl[0:15];                                  //运算器的控制信号
    reg [2:0] work_mode[0:15];                                 //运算模式，用来选择运算器 
    reg [4:0] address_select_index_1, mem_select_index_1, address_select_index_2, mem_select_index_2;
    reg address_select_ready_1, mem_select_ready_1, address_select_ready_2, mem_select_ready_2;

    //定义空闲队列，方便查找到空闲可用的保留站条目
    reg [4:0] freeQueue[0:15];
    reg [4:0] free_tail;
    reg [4:0] free_head;
    //保留站号
    reg [4:0] compare_save_no [0:31];

    //遍历需要的指针
    integer i, j;
    
    initial begin
        //初始化空闲队列指针
        free_head <= 0;
        free_tail <= 31;  //初始情况下，所有的保留站条目都是可用的，即队列是满的
        rs_ok <= 32'h00000000;
        rt_ok <= 32'h00000000;
        item_ok <= 32'h00000000;
        address_ok <= 32'h00000000;
        //初始化保留站和队列
        for (i=0; i<16; i=i+1) begin
            freeQueue[i] <= i;
            compare_save_no[i] <= i;
        end
    end

    //第一阶段分配的保留站的条目块号
    reg [4:0] save_no_1_stage1, save_no_2_stage1;
    reg save_en_1_stage1, save_en_2_stage1;
    //第一阶段需要向后传递的信号
    reg [11:0] pc_1_stage1, pc_2_stage1;
    reg [2:0] work_mode_1_stage1, work_mode_2_stage1;
    reg [31:0] imm_1_stage1, imm_2_stage1;
    reg [3:0] alu_ctrl_1_stage1, alu_ctrl_2_stage1;
    reg rs_1_ready_stage1, rt_1_ready_stage1;
    reg rs_2_ready_stage1, rt_2_ready_stage1;
    reg [4:0] rs_1_relation_stage1, rt_1_relation_stage1, rd_1_relation_stage1; 
    reg [4:0] rs_2_relation_stage1, rt_2_relation_stage1, rd_2_relation_stage1;
    reg [31:0] rs_1_value_stage1, rt_1_value_stage1, rs_2_value_stage1, rt_2_value_stage1;
    reg [2:0] dm_rd_ctrl_1_stage1, dm_rd_ctrl_2_stage1;  //RAM读取控制信号
    reg [1:0] dm_wr_ctrl_1_stage1, dm_wr_ctrl_2_stage1;  //RAM写入控制信号


    always @(posedge clk) begin
        //分配空闲保留站块
        if (save_en_1==1 && save_en_2==1 && (work_mode_1==3'b100 || work_mode_1==3'b101) && (work_mode_2==3'b100 || work_mode_2==3'b101)) begin
            save_no_1_stage1 <= freeQueue[free_head];
            save_no_2_stage1 <= freeQueue[(free_head+1)%16];
            //指针后移
            free_head <= (free_head+2)%16;
            save_en_1_stage1 <= 1;
            save_en_2_stage1 <= 1;
        end
        else if (save_en_1==1 && (work_mode_1==3'b100 || work_mode_1==3'b101)) begin
            save_no_1_stage1 <= freeQueue[free_head];
            //指针后移
            free_head <= (free_head+1)%16;
            save_en_1_stage1 <= 1;
            save_en_2_stage1 <= 0;
        end
        else if (save_en_2==1 && (work_mode_2==3'b100 || work_mode_2==3'b101)) begin
            save_no_2_stage1 <= freeQueue[free_head];
            //指针后移
            free_head <= (free_head+1)%16;
            save_en_1_stage1 <= 0;
            save_en_2_stage1 <= 1;
        end
        else begin
            save_en_1_stage1 <= 0;
            save_en_2_stage1 <= 0;
        end

        //将现在没用到的信号传递到下一级
        pc_1_stage1 <= pc_1;
        pc_2_stage1 <= pc_2;
        work_mode_1_stage1 <= work_mode_1;
        work_mode_2_stage1 <= work_mode_2;
        imm_1_stage1 <= imm_1;
        imm_2_stage1 <= imm_2;
        alu_ctrl_1_stage1 <= alu_ctrl_1; 
        alu_ctrl_2_stage1 <= alu_ctrl_2; 
        rs_1_ready_stage1 <= rs_1_ready;
        rt_1_ready_stage1 <= rt_1_ready;     
        rs_2_ready_stage1 <= rs_2_ready;     
        rt_2_ready_stage1 <= rt_2_ready;     
        rs_1_relation_stage1 <= rs_1_relation; 
        rt_1_relation_stage1 <= rt_1_relation; 
        rd_1_relation_stage1 <= rd_1_relation; 
        rs_2_relation_stage1 <= rs_2_relation;
        rt_2_relation_stage1 <= rt_2_relation;
        rd_2_relation_stage1 <= rd_2_relation;
        rs_1_value_stage1 <= rs_1_value;
        rt_1_value_stage1 <= rt_1_value;      
        rs_2_value_stage1 <= rs_2_value;
        rt_2_value_stage1 <= rt_2_value; 
        dm_rd_ctrl_1_stage1 <= dm_rd_ctrl_1;
        dm_rd_ctrl_2_stage1 <= dm_rd_ctrl_2;
        dm_wr_ctrl_1_stage1 <= dm_wr_ctrl_1;
        dm_wr_ctrl_2_stage1 <= dm_wr_ctrl_2;
    end

    //第二阶段，将指令内容存储在保留站结构中
    always @(posedge clk) begin
        if (save_en_1_stage1==1) begin
            //将数据写入到保留站备用
            rs_value[save_no_1_stage1] <= rs_1_value_stage1;
            rt_value[save_no_1_stage1] <= rt_1_value_stage1;
            rd_relation[save_no_1_stage1] <= rd_1_relation_stage1;
            work_mode[save_no_1_stage1] <= work_mode_1_stage1;   //Load & Store指令
            pc[save_no_1_stage1] <= pc_1_stage1;
            imm[save_no_1_stage1] <= imm_1_stage1;
            //存储对于存储器的读写控制信号
            dm_write_ctrl[save_no_1_stage1] <= dm_wr_ctrl_1_stage1;
            dm_read_ctrl[save_no_1_stage1] <= dm_rd_ctrl_1_stage1;
            alu_ctrl[save_no_1_stage1] <= 4'b0000;

            if (rs_1_ready_stage1==1) begin 
                //操作数rs，已经准备好
                rs_ok[save_no_1_stage1] <= 1;  
                //如果是访存指令，此时则可以进行访存地址的运算
                address_ok[save_no_1_stage1] <= 0;
            end
            else begin
                rs_ok[save_no_1_stage1] <= 0;
                rs_relation[save_no_1_stage1] <= rs_1_relation_stage1;
            end

            if (rt_1_ready==1) begin
                //操作数rt，已经准备好
                rt_ok[save_no_1_stage1] <= 1;
            end
            else begin
                rt_ok[save_no_1_stage1] <= 0;
                rt_relation[save_no_1_stage1] <= rt_1_relation_stage1;
            end         
        end

        if (save_en_2_stage1==1) begin
            //将数据写入到保留站备用
            rs_value[save_no_2_stage1] <= rs_2_value_stage1;
            rt_value[save_no_2_stage1] <= rt_2_value_stage1;
            rd_relation[save_no_2_stage1] <= rd_2_relation_stage1;
            work_mode[save_no_2_stage1] <= work_mode_2_stage1;
            imm[save_no_2_stage1] <= imm_2_stage1;
            pc[save_no_2_stage1] <= pc_2_stage1;
            //存储对于存储器的读写控制信号
            dm_write_ctrl[save_no_2_stage1] <= dm_wr_ctrl_2_stage1;
            dm_read_ctrl[save_no_2_stage1] <= dm_rd_ctrl_2_stage1;
            alu_ctrl[save_no_2_stage1] <= 4'b0000;


            if (rs_2_ready==1) begin
                rs_ok[save_no_2_stage1] <= 1;
                //标记其准备好
                address_ok[save_no_2_stage1] <= 0;
            end
            else begin
                rs_ok[save_no_2_stage1] <= 0;
                rs_relation[save_no_2_stage1] <= rs_2_relation;
                //标记其准备好
                address_ok[save_no_2_stage1] <= 0;
            end

            if (rt_2_ready==1) begin
                rt_ok[save_no_2_stage1] <= 1;
            end
            else begin
                rt_ok[save_no_2_stage1] <= 0;
                rt_relation[save_no_2_stage1] <= rt_2_relation;
            end          
        end
    end

    //运算结果的写回逻辑 -- 目前的想法是，以前的那个逻辑在仿真能够通过，但是可能要占据较大的面积
    always @(posedge clk) begin
        for (i=0; i<16; i=i+1) begin
            //如果的保留站条目确实在等待这个结果的写回，更新之
            if (alu_commit_en_1) begin
                if (rs_relation[i]==alu_commit_rob_no_1) begin
                    rs_value[i] <= alu_commit_value_1;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==alu_commit_rob_no_1) begin
                    rt_value[i] <= alu_commit_value_1;
                    rt_ok[i] <= 1;
                end
            end

            if (alu_commit_en_2) begin
                if (rs_relation[i]==alu_commit_rob_no_2) begin
                    rs_value[i] <= alu_commit_value_2;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==alu_commit_rob_no_2) begin
                    rt_value[i] <= alu_commit_value_2;
                    rt_ok[i] <= 1;
                end
            end

            if (mul_commit_en_1) begin
                if (rs_relation[i]==mul_commit_rob_no_1) begin
                    rs_value[i] <= mul_commit_value_1;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==mul_commit_rob_no_1) begin
                    rt_value[i] <= mul_commit_value_1;
                    rt_ok[i] <= 1;
                end
            end

            if (mul_commit_en_2) begin
                if (rs_relation[i]==mul_commit_rob_no_2) begin
                    rs_value[i] <= mul_commit_value_2;
                    rs_ok[i] <= 1;
                end
                
                if (rt_relation[i]==mul_commit_rob_no_2) begin
                    rt_value[i] <= mul_commit_value_2;
                    rt_ok[i] <= 1;
                end
            end
        end
    end
    
    //选择电路，在这里从保留站中选择需要执行的指令

    //发射电路，在这里将指令数据发射到地址运算部件
    always @(posedge clk) begin
        if (address_select_ready_1) begin
            address_ctrl_1 <= alu_ctrl[address_select_index_1];
            address_x_1 <= rs_value[address_select_index_1];
            address_y_1 <= imm[address_select_index_1];
            address_save_no_1 <= address_select_index_1;
            address_ready_en_1 <= 1;
        end
        else begin
            address_ready_en_1 <= 0;
        end

        if (address_select_ready_2) begin
            address_ctrl_2 <= alu_ctrl[address_select_index_2];
            address_x_2 <= rs_value[address_select_index_2];
            address_y_2 <= imm[address_select_index_2];
            address_save_no_2 <= address_select_index_2;
            address_ready_en_2 <= 1;
        end
        else begin
            address_ready_en_2 <= 0;
        end
    end

    
    //发射部件，在这里将指令数据发射到存储器部件
    always @(posedge clk) begin
        //第一条指令
        if (mem_select_ready_1) begin
            //LOAD
            if (work_mode[mem_select_index_1]==3'b100) begin
                mem_address_1 <= rs_value[mem_select_index_1];
                mem_save_no_1 <= mem_select_index_1;
                mem_rd_ctrl_1 <= dm_read_ctrl[mem_select_index_1];
                mem_rob_no_1 <= rd_relation[mem_select_index_1];
                mem_read_en_1 <= 1;
            end
            else begin
                mem_read_en_1 <= 0;
            end

            //STORE
            if (work_mode[mem_select_index_1]==3'b101) begin
                mem_address_1 <= rs_value[mem_select_index_1];
                mem_content_1 <= rt_value[mem_select_index_1];
                mem_save_no_1 <= mem_select_index_1;
                mem_wr_ctrl_1 <= dm_write_ctrl[mem_select_index_1];
                mem_rob_no_1 <= rd_relation[mem_select_index_1];
                mem_write_en_1 <= 1;
            end
            else begin
                mem_write_en_1 <= 0;
            end
        end
        else begin
            mem_read_en_1 <= 0;
            mem_write_en_1 <= 0;
        end

        //第二条指令
        if (mem_select_ready_2) begin
            //LOAD
            if (work_mode[mem_select_index_2]==3'b100) begin
                mem_address_2 <= rs_value[mem_select_index_2];
                mem_save_no_2 <= mem_select_index_2;
                mem_rd_ctrl_2 <= dm_read_ctrl[mem_select_index_2];
                mem_rob_no_2 <= rd_relation[mem_select_index_2];
                mem_read_en_2 <= 1;
            end
            else begin
                mem_read_en_2 <= 0;
            end

            //STORE
            if (work_mode[mem_select_index_2]==3'b101) begin
                mem_address_2 <= rs_value[mem_select_index_2];
                mem_content_2 <= rt_value[mem_select_index_2];
                mem_save_no_2 <= mem_select_index_2;
                mem_wr_ctrl_2 <= dm_write_ctrl[mem_select_index_2];
                mem_rob_no_2 <= rd_relation[mem_select_index_2];
                mem_write_en_2 <= 1;
            end
            else begin
                mem_write_en_2 <= 0;
            end
        end
        else begin
            mem_read_en_2 <= 0;
            mem_write_en_2 <= 0;
        end
    end
endmodule